package com.ruoyi.ring.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSONArray;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.TimeUnitEnums;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ring.domain.RingExerciseDetail;
import com.ruoyi.ring.domain.RingExerciseInfo;
import com.ruoyi.ring.domain.dto.GeneralSecondDTO;
import com.ruoyi.ring.domain.vo.*;
import com.ruoyi.ring.mapper.RingExerciseDetailMapper;
import com.ruoyi.ring.mapper.RingExerciseInfoMapper;
import com.ruoyi.ring.service.IExerciseDetailSecondService;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ExerciseDetailSecondServiceImpl implements IExerciseDetailSecondService {
    @Resource
    private RingExerciseDetailMapper exerciseDetailMapper;
    @Resource
    private RingExerciseInfoMapper exerciseInfoMapper;
    @Resource
    private SysUserMapper sysUserMapper;

    @Override
    public List<RingExerciseInfo> queryExerciseInfoList(GeneralSecondDTO secondDTO) {
        return exerciseInfoMapper.selectRingExerciseInfoList(new RingExerciseInfo());
    }

    @Override
    public AjaxResult queryExerciseList(GeneralSecondDTO secondDTO) {
        ExerciseDayListVO dayListVO = new ExerciseDayListVO();

        ExerciseInfoListVO exerciseInfoList = new ExerciseInfoListVO();
        List<ExerciseInfoListVO.ExerciseDayVO> exerciseDayVOS = new ArrayList<>();

        secondDTO.setUserId(SecurityUtils.getUserId());
        List<GeneralGroupVO> groupVOList = exerciseDetailMapper.queryExerciseList(secondDTO);
        String dateStart = "";
        String dateEnd = "";
        String recordDate = "";
        String weekName = "";

        List<ExerciseJsonVO> exerciseJsonVOS = new ArrayList<>();
        for (GeneralGroupVO group : groupVOList) {
            if (!TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())) {
                dateStart = group.getDateStart() + "，" + DateUtils.getChineseWeekday(group.getDateStart());
                dateEnd = group.getDateEnd() + "，" + DateUtils.getChineseWeekday(group.getDateEnd());
            }
            recordDate = group.getDailyValue();
            weekName = group.getWeekName();

            String groupData = group.getGroupData(); // 包含多条记录的JSON数组
            // 解析JSON数组为具体的实体类（假设有子实体类 BloodOxygenDetail）
            if (groupData != null) {
                JSONArray jsonArray = JSONArray.parseArray(groupData);
                List<ExerciseJsonVO> jsonObjectVOList = jsonArray.toJavaList(ExerciseJsonVO.class);
                exerciseJsonVOS = jsonObjectVOList.stream().sorted(Comparator.comparingLong(ExerciseJsonVO::getId).reversed()).collect(Collectors.toList());
            }
            if (TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())) {
                List<ExerciseJsonVO> exerciseVOS = new ArrayList<>();
                dayListVO.setRecordDate(recordDate);
                dayListVO.setWeekName(weekName);
                for (ExerciseJsonVO vo : exerciseJsonVOS) {
                    vo.setValidTime(vo.getValidTime() / 60);
                    exerciseVOS.add(vo);
                }
                dayListVO.setExerciseVOS(exerciseVOS);
            } else {
                List<ExerciseJsonVO> exerciseVOS = new ArrayList<>();
                exerciseInfoList.setDateStart(dateStart);
                exerciseInfoList.setDateEnd(dateEnd);
                ExerciseInfoListVO.ExerciseDayVO exerciseDayVO = new ExerciseInfoListVO.ExerciseDayVO();
                exerciseDayVO.setRecordDate(recordDate);
                exerciseDayVO.setWeekName(weekName);
                for (ExerciseJsonVO vo : exerciseJsonVOS) {
                    vo.setValidTime(vo.getValidTime() / 60);
                    exerciseVOS.add(vo);
                }
                exerciseDayVO.setExerciseVOS(exerciseVOS);
                exerciseDayVOS.add(exerciseDayVO);
                exerciseInfoList.setExerciseDayVOS(exerciseDayVOS);
            }
        }
        if (TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())) {
            return AjaxResult.success(dayListVO);
        } else {
            return AjaxResult.success(exerciseInfoList);
        }
    }

    @Override
    public ExerciseDetailVO queryExerciseDetail(Long id) {
        RingExerciseDetail ringExerciseDetail = exerciseDetailMapper.selectRingExerciseDetailById(id);
        ExerciseDetailVO exerciseDetailVO = new ExerciseDetailVO();
        if(ringExerciseDetail != null){
            exerciseDetailVO.setDistance(ringExerciseDetail.getDistance());
            exerciseDetailVO.setValidTime(DateUtils.convertMinutesToHHMM(Convert.toInt(ringExerciseDetail.getValidTime())));
            exerciseDetailVO.setCalories(ringExerciseDetail.getCalories());
            exerciseDetailVO.setPace(querypaceResult(ringExerciseDetail.getValidTime(), ringExerciseDetail.getDistance()));
            exerciseDetailVO.setSteps(ringExerciseDetail.getSteps());
            exerciseDetailVO.setStepRate(queryStepRate(ringExerciseDetail.getValidTime(), ringExerciseDetail.getSteps()));
            exerciseDetailVO.setAverageFrequency(queryStepRate(ringExerciseDetail.getValidTime(), ringExerciseDetail.getSteps()));
            String[] hrvInfos = ringExerciseDetail.getHrList().replace("null", "0").replace("255", "0").split(",");//转成String数组
            List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
            long average = Convert.toLong(hrvInfoList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
            exerciseDetailVO.setHrRate(average);
        }
        return exerciseDetailVO;
    }

    @Override
    public ExerciseHeartRateVO queryExerciseHeartRate(Long id) {
        RingExerciseDetail ringExerciseDetail = exerciseDetailMapper.selectRingExerciseDetailById(id);
        ExerciseHeartRateVO exerciseHeartRateVO = new ExerciseHeartRateVO();
        if(ringExerciseDetail != null){
            String[] hrvInfos = ringExerciseDetail.getHrList().replace("null", "0").replace("255", "0").split(",");//转成String数组
            List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
            long average = Convert.toLong(hrvInfoList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
            exerciseHeartRateVO.setHrRate(average);
            exerciseHeartRateVO.setMaxValue(hrvInfoList.stream().filter(num -> num != 0).max(Integer::compare).orElse(0));
            exerciseHeartRateVO.setMinValue(hrvInfoList.stream().filter(num -> num != 0).min(Integer::compare).orElse(0));
            exerciseHeartRateVO.setHrRates(hrvInfoList);
            exerciseHeartRateVO.setDateStart(DateUtils.convertDateTimeToHHMM(ringExerciseDetail.getStartTime()));
            exerciseHeartRateVO.setDateEnd(DateUtils.convertDateTimeToHHMM(ringExerciseDetail.getEndTime()));
        }
        return exerciseHeartRateVO;
    }
    // 初始化ObjectMapper，它是线程安全的，可以复用
    private static final ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public ExerciseIntervalVO queryExerciseInterval(Long id) {
        ExerciseIntervalVO exerciseIntervalVO = new ExerciseIntervalVO();
        RingExerciseDetail ringExerciseDetail = exerciseDetailMapper.selectRingExerciseDetailById(id);
        SysUser sysUser = sysUserMapper.queryUserHealthQuestion(SecurityUtils.getUserId());
        if(ringExerciseDetail != null && sysUser != null && sysUser.getBirthday() != null){
            String[] hrvInfos = ringExerciseDetail.getHrList().replace("null", "0").replace("255", "0").split(",");//转成String数组
            List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
            if(hrvInfoList.size() > 0){
                Map<String, Object> mapResult = calculateTimePerInterval(DateUtils.calculateAge(sysUser.getBirthday()),hrvInfoList,Convert.toDouble(ringExerciseDetail.getValidTime()));
                TypeReference<Map<String, Integer>> integerMapType = new TypeReference<Map<String, Integer>>() {};
                Map<String, Integer> hrvRresult = convertToTypedMap(mapResult,"hrvRresult",integerMapType);

                TypeReference<Map<String, Double>> doubleMapType = new TypeReference<Map<String, Double>>() {};
                Map<String, Double> timeResult = convertToTypedMap(mapResult,"timeResult",doubleMapType);
                int totalTime = Convert.toInt(mapResult.get("totalTime"));
                int totalRate = Convert.toInt(mapResult.get("totalRate"));

                int warHrv = hrvRresult.get("50");
                int fatHrv = hrvRresult.get("60");
                int heartHrv = hrvRresult.get("70");
                int enduranHrv = hrvRresult.get("80");
                int anaerHrv = hrvRresult.get("90");

                double war = timeResult.get("50");
                double fat = timeResult.get("60");
                double heart = timeResult.get("70");
                double enduran = timeResult.get("80");
                double anaer = timeResult.get("90");

                // 热身放松(50%-60%)
                exerciseIntervalVO.setWarmUpRelaxRate(totalRate > 0 ? Math.round((double) warHrv / totalRate * 100) : 0);
                exerciseIntervalVO.setWarmUpRelaxTime(war > 0 ? DateUtils.convertSecondsToChinese(Convert.toInt(war)) : "00小时00分钟");

                // 脂肪燃烧(60%-70%)
                exerciseIntervalVO.setFatBurningRate(totalRate > 0 ? Math.round((double) fatHrv / totalRate * 100) : 0);
                exerciseIntervalVO.setFatBurningTime(fat > 0 ? DateUtils.convertSecondsToChinese(Convert.toInt(fat)) : "00小时00分钟");

                // 心肺强化(70%-80%)
                exerciseIntervalVO.setHeartLungsRate(totalRate > 0 ? Math.round((double) heartHrv / totalRate * 100) : 0);
                exerciseIntervalVO.setHeartLungsTime(heart > 0 ? DateUtils.convertSecondsToChinese(Convert.toInt(heart)) : "00小时00分钟");

                // 耐力强化(80%-90%)
                exerciseIntervalVO.setEnduranceReinforcementRate(totalRate > 0 ? Math.round((double) enduranHrv / totalRate * 100) : 0);
                exerciseIntervalVO.setEnduranceReinforcementTime(enduran > 0 ? DateUtils.convertSecondsToChinese(Convert.toInt(enduran)) : "00小时00分钟");

                // 无氧极限(90%-100%)
                exerciseIntervalVO.setAnaerobicLimitRate(totalRate > 0 ? Math.round((double) anaerHrv / totalRate * 100) : 0);
                exerciseIntervalVO.setAnaerobicLimitTime(anaer > 0 ? DateUtils.convertSecondsToChinese(Convert.toInt(anaer)) : "00小时00分钟");

                exerciseIntervalVO.setTotalDuration(totalTime > 0 ?DateUtils.convertSecondsToChinese(totalTime) : "0小时0分钟");
            }
        }
        return exerciseIntervalVO;
    }

    /**
     * 计算配速
     */
    public String querypaceResult(Long validTime, Long distance) {
        if(validTime > 0 && distance > 0){
            // 距离（千米）
            double meters  = Convert.toDouble(distance) / 1000;
            // 计算每千米的时间（秒）
            double secondsPerKilometer = validTime / meters;
            // 转换为分钟和秒
            int minutes = (int) (secondsPerKilometer / 60);
            int seconds = (int) (secondsPerKilometer % 60);
            return minutes + "'" + seconds + "''";
        }else {
            return null;
        }
    }

    /**
     * 计算速率
     */
    public Long queryStepRate(Long validTime, Long steps) {
        if(validTime > 0 && steps > 0) {
            // 将总时间转换为分钟
            double totalMinutes = validTime / 60.0;
            // 计算速率（步/分钟）
            double stepRate = steps / totalMinutes;
            return Convert.toLong(stepRate);
        }else {
            return null;
        }
    }

    /**
     * 区间上下限
     * 计算公式为：
     * 区间下限 BPM = 最大心率（220-实际年龄）× 区间百分比下限
     * 区间上限 BPM = 最大心率（220-实际年龄）× 区间百分比上限
     */
    public static Map<String,Integer> queryUpperLowerResult(Integer age, Double upperRate,Double lowerRate){
        Map<String,Integer> map = null;
        if(age > 0){
            map = new HashMap<>();
            map.put("upper",Convert.toInt((220 - age) * Convert.toDouble(upperRate/100)));
            map.put("lower",Convert.toInt((220 - age) * Convert.toDouble(lowerRate/100)));
        }
        return map;
    }

    /**
     * 整合区间心率
     * @param age
     * @param hrvInfoList
     * @param validTime
     * @return
     */
    public static Map<String, Object> calculateTimePerInterval(Integer age, List<Integer> hrvInfoList, Double validTime) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Integer> hrvRresult = new HashMap<>();
        hrvRresult.put("50", 0);
        hrvRresult.put("60", 0);
        hrvRresult.put("70", 0);
        hrvRresult.put("80", 0);
        hrvRresult.put("90", 0);
        Map<String, Double> timeResult = new HashMap<>();
        timeResult.put("50", 0.0);
        timeResult.put("60", 0.0);
        timeResult.put("70", 0.0);
        timeResult.put("80", 0.0);
        timeResult.put("90", 0.0);
        int totalTime = 0;
        int totalRate = 0;
        // 心率区间定义 (百分比)
        int zone50 = 0; // 热身放松 (50%)
        int zone60 = 0; // 脂肪燃烧 (60%)
        int zone70 = 0; // 心肺强化 (80%)
        int zone80 = 0; // 耐力强化 (90%)
        int zone90 = 0; // 无氧极限 (100%)
        int number = hrvInfoList.size();
        if (number == 0) return null;
        //热身放松(50%-60%)
        Map<String,Integer>  warmUpRelaxMap = queryUpperLowerResult(age,Convert.toDouble(50),Convert.toDouble(60));
        //脂肪燃烧(60%-70%)
        Map<String,Integer>  fatBurningMap = queryUpperLowerResult(age,Convert.toDouble(60),Convert.toDouble(70));
        //心肺强化(70%-80%)
        Map<String,Integer>  heartLungsMap = queryUpperLowerResult(age,Convert.toDouble(70),Convert.toDouble(80));
        //耐力强化(80%-90%)
        Map<String,Integer>  enduranceReinforcementMap = queryUpperLowerResult(age,Convert.toDouble(80),Convert.toDouble(90));
        //无氧极限(90%-100%)
        Map<String,Integer>  anaerobicLimitwarmUpRelaxMap = queryUpperLowerResult(age,Convert.toDouble(90),Convert.toDouble(100));
        // --- 2. 计算平均心率间隔 ---
        int averageIntervalSeconds = Convert.toInt(Math.round(validTime / number));
        for (int heartRate : hrvInfoList) {
            // 跳过无效的心率值（例如0）
            if (heartRate <= 0) {
                continue;
            }
            // 根据心率值，累加到对应的区间
            if (heartRate >= warmUpRelaxMap.get("upper") && heartRate < warmUpRelaxMap.get("lower")) {
                timeResult.put("50", timeResult.get("50") + averageIntervalSeconds);
                zone50 += heartRate;
                totalTime += averageIntervalSeconds;
                totalRate += heartRate;
            } else if (heartRate >= fatBurningMap.get("upper") && heartRate <  fatBurningMap.get("lower")) {
                timeResult.put("60", timeResult.get("60") + averageIntervalSeconds);
                zone60 += heartRate;
                totalTime += averageIntervalSeconds;
                totalRate += heartRate;
            } else if (heartRate >= heartLungsMap.get("upper") && heartRate <  heartLungsMap.get("lower")) {
                timeResult.put("70", timeResult.get("70") + averageIntervalSeconds);
                zone70 += heartRate;
                totalTime += averageIntervalSeconds;
                totalRate += heartRate;
            } else if (heartRate >= enduranceReinforcementMap.get("upper") && heartRate <  enduranceReinforcementMap.get("lower")) {
                timeResult.put("80", timeResult.get("80") + averageIntervalSeconds);
                zone80 += heartRate;
                totalTime += averageIntervalSeconds;
                totalRate += heartRate;
            } else if (heartRate >= anaerobicLimitwarmUpRelaxMap.get("upper") && heartRate <  anaerobicLimitwarmUpRelaxMap.get("lower")) {
                timeResult.put("90", timeResult.get("90") + averageIntervalSeconds);
                zone90 += heartRate;
                totalTime += averageIntervalSeconds;
                totalRate += heartRate;
            }
        }
        hrvRresult.put("50",zone50);
        hrvRresult.put("60",zone60);
        hrvRresult.put("70",zone70);
        hrvRresult.put("80",zone80);
        hrvRresult.put("90",zone90);
        result.put("timeResult",timeResult);
        result.put("hrvRresult",hrvRresult);
        result.put("totalTime",totalTime);
        result.put("totalRate",totalRate);
        return result;
    }

    // 通用转换方法
    private <K, V> Map<K, V> convertToTypedMap(Map<String, Object> sourceMap, String key, TypeReference<Map<K, V>> typeReference) {
        Object value = sourceMap.get(key);
        if (value == null) {
            // 根据业务需求，这里可以返回空 Map 或者抛出异常
            return new HashMap<>();
        }
        return objectMapper.convertValue(value, typeReference);
    }
}
